/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "LightVisualizer.h"

#include "SceneObject.h"

namespace PQEngine
{
	const Ogre::String LightVisualizer::LIGHT_MANUAL_OBJ_NAME="Visualizer/Light/Manual";
	const Ogre::String LightVisualizer::LIGHT_MATERIAL_NAME="Visualizer/Light/Material";
	const Ogre::String LightVisualizer::LIGHT_ENTITY_NAME="Visualizer/Light/Entity";

	LightVisualizer::LightVisualizer(SceneObject* sceneObject)
		: _sceneObject(sceneObject),_lightType(Ogre::Light::LT_POINT),
		_outerAngle(Ogre::Degree(60.0f)),_innerAngle(Ogre::Degree(50.0f)),
		_attenuationRange(100.0f),_selected(false)
	{
		assert(_sceneObject);
		_sceneManager=_sceneObject->getSceneManager();
		createLightVisualizer();
		show(true);
	}

	void LightVisualizer::createLightVisualizer()
	{
		_visualObject=_sceneManager->createManualObject(LIGHT_MANUAL_OBJ_NAME);
		_visualObject->estimateIndexCount(0);
		_visualObject->estimateVertexCount(MODEL_VERTEX_COUNT);
		_visualObject->setDynamic(true);

		//we may put all visiualizer and gizmo to a special group.Now put in general.
		_material=Ogre::MaterialManager::getSingleton().create(LIGHT_MATERIAL_NAME,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		_material->setReceiveShadows(false);
		_material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
		_material->getTechnique(0)->getPass(0)->setVertexColourTracking(Ogre::TVC_DIFFUSE);

		 //Create 5 sections, four Line strip (for max. 4 circles) and one Line list version
		for(int i=0;i<5;i++){
			if(i<4){
				_visualObject->begin(_material->getName(),Ogre::RenderOperation::OT_LINE_STRIP);
			}else{
				_visualObject->begin(_material->getName(),Ogre::RenderOperation::OT_LINE_LIST);
			}
			_visualObject->position(0,0,0);
			_visualObject->colour(1,1,1);
			_visualObject->position(0,0,0);
			_visualObject->colour(1,1,1);
			_visualObject->end();
		}

		_visualObject->setVisible(false);
		_sceneNode->attachObject(_visualObject);

		setLightType(_lightType);
		
	}

	void LightVisualizer::setLightType(Ogre::Light::LightTypes type)
	{
		switch(type){
			case Ogre::Light::LT_POINT:
				createPointLightGizmo();
				break;
			case Ogre::Light::LT_DIRECTIONAL:
				createDirectionalLightGizmo();
				break;
			case Ogre::Light::LT_SPOTLIGHT:
				createSpotLightGizmo();
				break;
		}
	}

	void LightVisualizer::createPointLightGizmo()
	{
	}

	void LightVisualizer::createDirectionalLightGizmo()
	{
		Ogre::Real radius=2.0f;
		Ogre::Real length=6.0f;

		Ogre::ColourValue color1(0.6f, 0.8f, 0.9f);
		Ogre::ColourValue color2(0.3f, 0.4f, 0.45f);

		// draw circles
		_visualObject->beginUpdate(0);
		drawCircle(radius,0,color1);
		_visualObject->end();

		_visualObject->beginUpdate(1);
		drawCircle(radius,length,color1);
		_visualObject->end();

		// empty sections
		_visualObject->beginUpdate(2);
		_visualObject->end();
		_visualObject->beginUpdate(3);
		_visualObject->end();
		
		 // draw four lines between both circles
		_visualObject->beginUpdate(4);
		//line 1
		_visualObject->position(radius,0,0);
		_visualObject->colour(color1);
		_visualObject->position(radius,0,length);
		_visualObject->colour(color1);
		//line 2
		_visualObject->position(0,radius,0);
		_visualObject->colour(color1);
		_visualObject->position(0,radius,length);
		_visualObject->colour(color1);
		//line 3
		_visualObject->position(0,-radius,0);
		_visualObject->colour(color1);
		_visualObject->position(0,-radius,length);
		_visualObject->colour(color1);
		//line 4
		_visualObject->position(-radius,0,0);
		_visualObject->colour(color1);
		_visualObject->position(-radius,0,length);
		_visualObject->colour(color1);
		_visualObject->end();

	}

	void LightVisualizer::createSpotLightGizmo()
	{
		Ogre::ColourValue color1(0.6f, 0.8f, 0.9f);
		Ogre::ColourValue color2(0.3f, 0.4f, 0.45f);
		
		Ogre::Real spotlightStartCircleOffset=0.65f;
		Ogre::Real firstInnerRadius = Ogre::Math::Tan(_innerAngle/2) * spotlightStartCircleOffset;
		Ogre::Real secondInnerRadius = Ogre::Math::Tan(_innerAngle/2) * _attenuationRange;
		Ogre::Real firstOuterRadius = Ogre::Math::Tan(_outerAngle/2) * spotlightStartCircleOffset;
		Ogre::Real secondOuterRadius = Ogre::Math::Tan(_outerAngle/2) * _attenuationRange;

		// draw inner circles
		_visualObject->beginUpdate(0);
		drawCircle(firstInnerRadius,spotlightStartCircleOffset,color2);
		_visualObject->end();

		_visualObject->beginUpdate(1);
		drawCircle(secondInnerRadius,_attenuationRange,color2);
		_visualObject->end();

		//draw outer circles
		_visualObject->beginUpdate(2);
		drawCircle(firstOuterRadius,spotlightStartCircleOffset,color1);
		_visualObject->end();

		_visualObject->beginUpdate(3);
		drawCircle(secondOuterRadius,_attenuationRange,color1);
		_visualObject->end();

		_visualObject->beginUpdate(4);
	   // draw 4 lines between inner circles
	   _visualObject->position(firstInnerRadius,0,spotlightStartCircleOffset);
	   _visualObject->colour(color2);
	   _visualObject->position(secondInnerRadius,0,_attenuationRange);
	   _visualObject->colour(color2);
	   _visualObject->position(0,firstInnerRadius,spotlightStartCircleOffset);
	   _visualObject->colour(color2);
	   _visualObject->position(0,secondInnerRadius,_attenuationRange);
	   _visualObject->colour(color2);
	   _visualObject->position(0,-firstInnerRadius,spotlightStartCircleOffset);
	   _visualObject->colour(color2);
	   _visualObject->position(0,-secondInnerRadius,_attenuationRange);
	   _visualObject->colour(color2);
	   _visualObject->position(-firstInnerRadius,0,spotlightStartCircleOffset);
	   _visualObject->colour(color2);
	   _visualObject->position(-secondInnerRadius,0,_attenuationRange);
	   _visualObject->colour(color2);

	   // draw 4 lines between outer circles
	   _visualObject->position(firstOuterRadius,0,spotlightStartCircleOffset);
	   _visualObject->colour(color1);
	   _visualObject->position(secondOuterRadius,0,_attenuationRange);
	   _visualObject->colour(color1);
	   _visualObject->position(0,firstOuterRadius,spotlightStartCircleOffset);
	   _visualObject->colour(color1);
	   _visualObject->position(0,secondOuterRadius,_attenuationRange);
	   _visualObject->colour(color1);
	   _visualObject->position(0,-firstOuterRadius,spotlightStartCircleOffset);
	   _visualObject->colour(color1);
	   _visualObject->position(0,-secondOuterRadius,_attenuationRange);
	   _visualObject->colour(color1);
	   _visualObject->position(-firstOuterRadius,0,spotlightStartCircleOffset);
	   _visualObject->colour(color1);
	   _visualObject->position(-secondOuterRadius,0,_attenuationRange);
	   _visualObject->colour(color1);
	   _visualObject->end();

	}

	void LightVisualizer::setModelMesh(Ogre::String meshName)
	{
		if(_entity){
			_entity->detachFromParent();
			_entity->_getManager()->destroyEntity(_entity);

		}
		
		_entity=_sceneManager->createEntity(LIGHT_ENTITY_NAME,meshName);
		//_entity->setQueryFlags();
		_entity->setCastShadows(false);
		_sceneNode->attachObject(_entity);
	}

	void LightVisualizer::drawCircle(const Ogre::Real radius, const Ogre::Real z, const Ogre::ColourValue& color)
	{
	   for (int i = 0; i <= CIRCLE_VETEX_COUNT; i++){
		  Ogre::Real x = Ogre::Math::Cos(Ogre::Radian((Ogre::Math::TWO_PI*i)/CIRCLE_VETEX_COUNT)) * radius;
		  Ogre::Real y = Ogre::Math::Sin(Ogre::Radian((Ogre::Math::TWO_PI*i)/CIRCLE_VETEX_COUNT)) * radius;
		  _visualObject->position(x, y, z);
		  _visualObject->colour(color);
	   }
	}

	void LightVisualizer::setSpotRange(Ogre::Degree innerAngle,Ogre::Degree outerAngle)
	{
		_innerAngle = innerAngle;
		_outerAngle = outerAngle;
		setLightType(_lightType);
	}

	void LightVisualizer::setSpotAttenuation(Ogre::Real attenuationRange)
	{
		_attenuationRange=attenuationRange;
		setLightType(_lightType);
	}

	void LightVisualizer::show(bool show)
	{
		_show=show;
		
		if(_entity){
			_entity->setVisible(show);
		}
		
		_visualObject->setVisible(_show&&_selected);
	}

	void LightVisualizer::select(bool selected)
	{
		_selected=selected;
	}


}
